package com.lx.boot.web.filter;

import com.lx.annotation.Note;
import com.lx.boot.OS;
import com.lx.boot.web.config.ApiProperties;
import com.lx.boot.web.config.RequestInfo;
import com.lx.constant.DefaultResult;
import com.lx.util.LX;
import com.lx.util.secure.algorithm.coder.Base64;
import com.lx.util.secure.algorithm.encrypt.Aes;
import com.lx.util.secure.algorithm.encrypt.Rsa;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Note("对body使用AES加密 aes密钥使用RSA进行加密")
@Component("rsaAesEncryptApiFilter")
public class RsaAesEncryptApiEncryptFilter extends ApiEncryptFilter {

    /**
     String aesKey = LX.uuid32(); //生成随机字符串aeskey 32位
     Aes aes = new Aes().key(aesKey);
     String bodyStr = aes.encryptToString(LX.toJSONString(data)); //对请求体进行aes加密并转为base64字符串
     String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuaYC7O7K1iOQldiIcESJ7Xzm65PGcYdJ5+H0CHc+BAcr/Ump9gyTiugiul+M/uvpq+7SUdRjQvuT36KNUKjz9spVa29vcLXpmrPsWcXFOxOZDUBcJQsbupPn7YaRax0ZXyZ6MKLggKk6Li8B6t1HfUDTQXUd01NYlW31y4hh4KojJR1RpXRU3kuQyB+18xGK0LwXssjbSVUh/uu1/WJPCiRDbkgfYUlGEm5rLU+tKSYb/wFJVY2ZV3gGGAB7D6h9Fzsp7VMGiC2BAcGMg/cc0xbIKPyCl5dlvnPdJ8om7QoVc3Ygi2y4YDJYdF+fXfWONPX9B2+GJvoXPVSSRTPCeQIDAQAB";
     String rsaAeskey = Rsa.publicKey(publicKey).encryptToString(aesKey);//使用公钥对aeskey进行加密 并转为Base64字符串
     //请求头map
     Map<String, String> headerMap = new HashMap<>();
     headerMap.put("rsaAeskey",rsaAeskey); //请求头放入加密后的aeskey
     headerMap.put("rsaTimestamp",aes.encryptToString(System.currentTimeMillis()+"")); //对时间戳aes加密并转为Base64字符串
     //使用请求头与请求体进行http的post请求
     System.out.println(LX.http("http://127.0.0.1:8888/test/test5").body(bodyStr).headers(headerMap).send());
     */
    @Override
    protected RequestWrapper getRequestWrapper(HttpServletRequest request, byte[] bodys, boolean notEncryptionUrl) throws IOException {
        Aes aes = getAes(request);
        if (!isPostOrPut(request) || notEncryptionUrl){
            return new RequestWrapper(request, bodys);
        }
        byte [] requestBody = aes.decrypt(Base64.getCoder().decode(bodys));
        log.info("url==>{} 实际请求参数:{}",request.getServletPath() ,LX.byteArrayToString(requestBody,5000));
        return new RequestWrapper(request, requestBody);
    }

    private static  final String RSA_AES = "RSA-AES";
    @Note("获取解密密钥")
    public Aes getAes(HttpServletRequest request){
        Aes aes = (Aes)request.getAttribute(RSA_AES);
        if (aes != null){
            return aes;
        }
        String rsaAeskey = request.getHeader("rsaAeskey");
        String rsaTimestamp = request.getHeader("rsaTimestamp");
        LX.exObj(rsaAeskey,"解密失败, 请检查参数!");
        LX.exObj(rsaTimestamp,"解密失败, 请检查参数!");
        String appid = LX.ifEmpty(request.getHeader("appid"),"default");
        ApiProperties apiProperties = OS.getBeanProperty(ApiProperties.class,"server.api."+appid);
        LX.exObj(apiProperties.getPrivateKey(),"请检查server.api."+appid+".privateKey是否配置!");
        String ip = OS.getIp(request);
        if (LX.isNotEmpty(apiProperties.getWhiteList()) && !ip.matches(apiProperties.getWhiteList())){
            log.info("ip:{}, 实际配置:{}",ip, apiProperties.getWhiteList());
            OS.responseErrorResult(DefaultResult.IP_LIMIT.setMessage("调用IP异常:"+ip));
            throw new RuntimeException("调用IP异常:"+ip);
        }
        Rsa rsa = Rsa.privateKey(apiProperties.getPrivateKey());
        String aesKey = rsa.decryptToString(rsaAeskey);
        aes = new Aes().key(aesKey);
        request.setAttribute(RSA_AES, aes);
        String timestamp = aes.decryptToString(rsaTimestamp);
        checkApiTimeAndRepeat(timestamp, aesKey);
        return aes;
    }


    @Override
    protected ResponseWrapper getResponseWrapper(ResponseWrapper responseWrapper,boolean returnEncryption) throws Exception {
        if (!returnEncryption){ //对返回值加密
            return responseWrapper;
        }
        byte[] bytes = getAes(OS.getRequest()).encryptToEncoder(responseWrapper.getContent()).getBase64String().getBytes(StandardCharsets.UTF_8);
        responseWrapper.setContent(bytes);
        return responseWrapper;
    }

}
